package hk.ust.comp3111.ustnutrition.data.db;

import hk.ust.comp3111.ustnutrition.MiscUtils;
import hk.ust.comp3111.ustnutrition.data.DataAccessor;

import java.util.Date;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class User extends AppConfig
{
	public enum ExerciseLevel
	{
		ALWAYS(0),
		SOMETIMES(1),
		SELDOM(2);

	    private final int value;
	    private ExerciseLevel(int value) {
	        this.value = value;
	    }
	    public int getValue() {
	        return value;
	    }
	    public static ExerciseLevel getValue(int value) {
	    	switch(value) {
	    	case 0:
	    		return ALWAYS;
	    	case 1:
	    		return SOMETIMES;
	    	case 2:
	    		return SELDOM;
	    	}
	    	return null;
	    }
	}

	public User()
	{
		mName = "";
		mIsFemale = true;
		mAge = 18;
		mHeight = 170;
		mWeight = 60;
		mExercise = ExerciseLevel.SOMETIMES;
		mIsJoinRanking = true;
	}

	public User(String name, boolean isFemale, int age, int height, int weight,
			ExerciseLevel exercise, boolean isJoinRanking)
	{
		mName = name;
		mIsFemale = isFemale;
		mAge = age;
		mHeight = height;
		mWeight = weight;
		mExercise = exercise;
		mIsJoinRanking = isJoinRanking;
	}

	public String getEmail()
	{
		return mEmail;
	}
	
	static Pattern itscPattern = Pattern.compile("^([A-Z._]+)@[A-Z.]*ust\\.hk$", Pattern.CASE_INSENSITIVE);
	
	String mITSC;
	
	public String getITSC()
	{
		return mITSC;
	}

	private String getITSCCore() {
		if(mEmail != null && mToken != null) {
			Matcher matcher = itscPattern.matcher(mEmail);
			if(matcher.find())
				return matcher.group(1);
		}
		return null;
	}

	public String getToken()
	{
		return mToken;
	}

	public String getName()
	{
		return mName;
	}

	public boolean isFemale()
	{
		return mIsFemale;
	}

	public int getAge()
	{
		return mAge;
	}

	public int getHeight()
	{
		return mHeight;
	}

	public int getWeight()
	{
		return mWeight;
	}

	public ExerciseLevel getExercise()
	{
		return mExercise;
	}

	public boolean isJoinRanking()
	{
		return mIsJoinRanking;
	}
	
	public double[] getNutritions()
	{
		return getNutritions(new Date());
	}

	public double[] getNutritions(Date date)
	{
		double[] value = new double[5];
		for(IntakeRecord record : DataAccessor.Instance.getRecords().getQuery("byDate").setKey(MiscUtils.getDate(date))) {
			Food food = record.getFood();
			if(food == null)
				continue;
			value[0] += food.getEnergy();
			value[1] += food.getCarbohydrate();
			value[2] += food.getProtein();
			value[3] += food.getFat();
			value[4] += food.getSodium();
		}
		return value;
	}

	public boolean logon()
	{
		return mToken != null && mEmail != null;
	}

	private String mToken;
	private String mEmail;
	private String mName;
	private boolean mIsFemale;
	private int mAge;
	private int mHeight;
	private int mWeight;
	private ExerciseLevel mExercise;
	private boolean mIsJoinRanking;

	@Override
	public void loadInfo(Map<String, Object> obj) {
		super.loadInfo(obj);
		mName = MiscUtils.get(obj, "name", "");
		mToken = (String) obj.get("token");
		mEmail = (String) obj.get("email");
		mIsFemale = MiscUtils.get(obj, "female", true);
		mAge = MiscUtils.get(obj, "age", 18);
		mHeight = MiscUtils.get(obj, "height", 170);
		mWeight = MiscUtils.get(obj, "weight", 60);
		mExercise = ExerciseLevel.getValue(MiscUtils.get(obj, "exercise", 1));
		if(mExercise == null)
			mExercise = ExerciseLevel.SOMETIMES;
		mIsJoinRanking = MiscUtils.get(obj, "joinRanking", true);
		mITSC = getITSCCore();
	}

	@Override
	public void putInfo(Map<String, Object> obj) {
		super.putInfo(obj);
		obj.put("name", mName);
		obj.put("token", mToken);
		obj.put("email", mEmail);
		obj.put("female", mIsFemale);
		obj.put("age", mAge);
		obj.put("height", mHeight);
		obj.put("weight", mWeight);
		obj.put("exercise", mExercise.getValue());
		obj.put("joinRanking", mIsJoinRanking);
	}

	public void update(User user) {
		update(user.mName, user.mIsFemale, user.mAge, user.mHeight, user.mWeight,
				user.mExercise, user.mIsJoinRanking);
	}

	public void update(String name, boolean isFemale, int age, int height,
			int weight, ExerciseLevel exercise, boolean isJoinRanking) {
		mName = name;
		mIsFemale = isFemale;
		mAge = age;
		mHeight = height;
		mWeight = weight;
		mExercise = exercise;
		mIsJoinRanking = isJoinRanking;
		mITSC = getITSCCore();
		commit();
	}

	public void login(String email, String token) {
		DataAccessor.Instance.beginUpdateChannel();
		mEmail = email;
		mToken = token;
		mITSC = getITSCCore();
		commit();
		DataAccessor.Instance.endUpdateChannel();
	}

	public void setEmail(String email) {
		DataAccessor.Instance.beginUpdateChannel();
		mEmail = email;
		mToken = null;
		mITSC = getITSCCore();
		commit();
		DataAccessor.Instance.endUpdateChannel();
	}
}

